#pragma ident "$Id: RinexAmbData.cpp 2897 2012-08-10 20:08:46Z shjzhang $"

/**
 * @file RinexAmbData.cpp
 * Encapsulate satellite upd file data, including I/O
 */

//============================================================================
//
//  Shoujian Zhang, Wuhan University, 2012
//
//============================================================================

#include "RinexAmbStream.hpp"
#include "RinexAmbData.hpp"
#include "StringUtils.hpp"
#include "TimeString.hpp"
#include "YDSTime.hpp"
#include "CivilTime.hpp"

using namespace gpstk::StringUtils;
using namespace std;

#define debug 0

namespace gpstk
{

   void RinexAmbData::reallyPutRecord(FFStream& ffs) const
      noexcept(false)
   {
         // cast the stream to be an RinexAmbStream
      RinexAmbStream& strm = dynamic_cast<RinexAmbStream&>(ffs);

      int i;
      string line;
      strm << line << endl;
      strm.lineNumber++;

   }  // end reallyPutRecord()

   void RinexAmbData::reallyGetRecord(FFStream& ffs)
      noexcept(false)
   {
         // cast the stream to be an RinexAmbStream
      RinexAmbStream& strm = dynamic_cast<RinexAmbStream&>(ffs);

      clear();

      try
      {
          while(true)
          {
              string line;
              strm.formattedGetLine(line,true);      // true means 'expect possible EOF'
              stripTrailing(line);
              if(line.length() < 48)
              {
                 FFStreamError e("Short line : " + line);
                 GPSTK_THROW(e);
              }

              if(debug)
              cout << "Data Line: /" << line << "/" << endl;

              vector<string> dataVec = split(line, " ");

              YDSTime ydsTime ( asInt(dataVec[0]),
                                asInt(dataVec[1]),
                                asDouble(dataVec[2]),
                                TimeSystem::Any);

              // Convert to CommonTime
              newTime = ydsTime.convertToCommonTime();

              std::string site;
              SatID sat;

              // site
              site = dataVec[3];

              SourceID source(SourceID::Mixed, site);

              // sat 
              std::string satStr = dataVec[4];
              int prn(asInt(satStr.substr(1,2)));
              if(satStr[0] == 'G')
              {
                 sat = SatID(prn, SatelliteSystem::GPS);
              }
              else if(satStr[0] == 'R')
              {
                 sat = SatID(prn,SatelliteSystem::GLONASS);
              }
              else if(satStr[0] == 'E')
              {
                 sat = SatID(prn,SatelliteSystem::Galileo);
              }
              else if(satStr[0] == 'C')
              {
                 sat = SatID(prn,SatelliteSystem::BDS);
              }

              int satArc;
              TypeID type;
              double estValue, varValue;
              int arcSize(0);

              // now, arc
              satArc = asInt(dataVec[5]);

              // now, the data record for type
              type = TypeID(strip(dataVec[6]));

              // now, read the est data
              estValue = asDouble(dataVec[7]);

              // now, the var value
              varValue = asDouble(dataVec[8]);

              // now, the arc-size
              if(dataVec.size() > 10 ) 
                  arcSize = asInt(dataVec[10]);

              if(debug)
                  cout << site << " " 
                       << sat << " "
                       << satArc << " "
                       << type << " "
                       << estValue << " "
                       << varValue << " "
                       << arcSize << " "
                       << endl;

              Variable var(type);
              var.setSource(source);
              var.setSatellite(sat);
              var.setArc(satArc);

              EstData estData;
              estData.value = estValue;
              estData.variance = varValue;

              // now, insert the est/var data into epochSiteSatEstData
              VariableEstDataMap ambEstData = epochAmbEstData[newTime];
              ambEstData[var] = estData;
              epochAmbEstData[newTime] = ambEstData;

              if(newTime > oldTime )
              {
                  if(firstEpoch)
                  {
                      oldTime = newTime;
                      firstEpoch = false;
                  }
                  else
                  {
                      currentAmbEstData = epochAmbEstData[oldTime];
                      epochAmbEstData.erase(oldTime);

                      currentTime = oldTime;

                      // update the time
                      oldTime = newTime;

                      // finish reading of current epoch
                      break;
                  }
              } // end if

          } // end while
      }
      catch(EndOfFile& e)
      {
          currentTime = oldTime;

          currentAmbEstData = epochAmbEstData[oldTime];
          epochAmbEstData.erase(oldTime);

          if(debug)
          {
              for(auto iter=currentAmbEstData.begin();
                       iter!=currentAmbEstData.end();
                       iter++)
              {
                  cout << (*iter).first << (*iter).second.value<< endl;
              }
              cout << endl;
          }
          // rethrow
          GPSTK_RETHROW(e);

      }
      catch(Exception& e)
      {
          currentTime = oldTime;

          currentAmbEstData = epochAmbEstData[oldTime];
          epochAmbEstData.erase(oldTime);

          // rethrow
          GPSTK_RETHROW(e);
      }

   }   // end reallyGetRecord()

   void RinexAmbData::dump(ostream& s) const throw()
   {
      // dump record type, sat id / site, current epoch, and data
      s << " " << printTime(currentTime,"%Y/%02m/%02d %2H:%02M:%06.3f = %F/%10.3g %P") << endl;
      for(auto iter=currentAmbEstData.begin();iter!=currentAmbEstData.end();iter++)
      {
         s << (*iter).first << " " << (*iter).second.value<< endl;
      }
      s << endl;

   }  // end dump()

} // namespace

//------------------------------------------------------------------------------------
